package com.hup.utils.swing.customView.colorChooser;

import com.hup.utils.commons.hardware.MouseUtil;
import com.hup.utils.swing.customView.ImageButton;
import com.hup.utils.swing.screenShot.ScreenShotUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
import javax.swing.border.TitledBorder;
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * 颜色选择器:集合了多个[不同的调色控件]的调色面板;本类是也一个[调色控件]的实现类
 *
 * @author hugan
 * @apiNote 可以直接调用 {@link #showDialog(Window, Color)}打开独立窗口;
 * 也可以嵌入到业务面板上,配合 {@link #setColorInvoker(ColorInvoker)}实现颜色监听
 * @date 2020/4/10
 */
@Log4j2
public class ColorChooserPanel extends JPanel implements IColorComponent {

    /**
     * 打开ui阻塞的颜色选择dialog
     *
     * @param parent nullable,用于处理置顶问题
     * @param initColor nullable,初始化的颜色
     * @return 被选中的颜色:notNull-选中颜色;null-取消选择,关闭窗口
     */
    public static Color showDialog(Window parent, Color initColor) {
        return showDialog(parent, initColor, ModalityType.DOCUMENT_MODAL);
    }

    public static Color showDialog(Window parent, Color initColor, ModalityType modalityType) {
        JDialog dialog = new JDialog(parent, "颜色选择器");
        dialog.setModalityType(modalityType);//用默认的话,会导致[屏幕取色窗]无法显示
        ColorChooserDialogForm form = new ColorChooserDialogForm();
        dialog.setContentPane(form.root);
        dialog.pack();
        dialog.setLocationRelativeTo(parent);
        if (parent != null && parent.isAlwaysOnTop()) dialog.setAlwaysOnTop(true);

        //取消按钮和关闭窗口都是dispose
        form.root.registerKeyboardAction(e -> dialog.dispose(),
                KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        form.btnCancel.addActionListener(e -> dialog.dispose());
        form.btnOK.addActionListener(e -> {
            //用于标记结果状态
            form.btnCancel.setEnabled(false);
            dialog.dispose();
        });
        if (initColor != null) form.colorChooser.updateTo(initColor);

        dialog.setVisible(true);//打开窗口并阻塞ui,直到窗口关闭
        if (form.btnCancel.isEnabled()) {
            return null;
        }
        return form.colorChooser.getColor();
    }

    private JPanel root;

    @Getter
    private RectangleColorLabel colorLabel;
    private NearColorLabel nearColorLabel;
    private BrightnessLabel brightnessLabel;
    private TransparencyLabel transparencyPanel;

    private ColorTextField txtColorInt;
    private ColorTextField txtColorHex;
    public ImageButton btnPipet;

    private List<IColorComponent> innerColorComponents;

    @Getter
    private Color color = new Color(80, 217, 255);
    /**
     * 外部的颜色变化[订阅者]
     */
    @Setter
    @Getter
    private ColorInvoker colorInvoker;

    public ColorChooserPanel() {
        $$$setupUI$$$();
        innerColorComponents = new ArrayList<>();
        innerColorComponents.add(colorLabel);
        innerColorComponents.add(nearColorLabel);
        innerColorComponents.add(brightnessLabel);
        innerColorComponents.add(transparencyPanel);
        innerColorComponents.add(txtColorInt);
        innerColorComponents.add(txtColorHex);

        initListener();

        log.debug("更新子组件颜色color={}", color);
        updateTo(color);
    }

    private void initListener() {
        ColorInvoker innerColorInvoker = (source, color) -> {
            //内部的[调色控件]触发整个面板更新颜色
            this.color = color;
            innerColorComponents.forEach(cc -> {
                if (cc != source) cc.updateTo(color);
            });
            //通知外部
            if (colorInvoker != null) colorInvoker.fireColorChanged(this, color);
        };
        innerColorComponents.forEach(cc -> cc.setColorInvoker(innerColorInvoker));

        //滚轮控制亮度
        addMouseWheelListener(e -> {
            int rotation = e.getWheelRotation();
            boolean isUp = rotation < 0;
            //一个滚轮单位,移动n个亮度值
            rotation = Math.abs(rotation) * (e.isControlDown() ? 30 : 5);

            log.debug("rotation={}", rotation);
            brightnessLabel.shiftBrightness(isUp, rotation);
        });

        //右键控制透明度
        MouseAdapter MouseAlphaListener = new MouseAdapter() {
            /**
             * 每个透明度刻度的像素宽度,随界面变化而变的
             */
            double pxPerAlpha;
            boolean isRight;
            public int x0;
            public int alpha0;

            @Override
            public void mousePressed(MouseEvent e) {
                if (MouseUtil.isRightButton(e)) {
                    pxPerAlpha = 256.0 / transparencyPanel.getWidth();
                    isRight = true;
                    x0 = e.getXOnScreen();
                    alpha0 = color.getAlpha();
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                if (MouseUtil.isRightButton(e)) isRight = false;
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                if (isRight) {
                    int diff = (int) ((e.getXOnScreen() - x0) * pxPerAlpha);
                    int alpha = alpha0 + diff;
                    if (alpha < 0) alpha = 0;
                    else if (alpha > 255) alpha = 255;
                    if (alpha != alpha0) {
                        //log.info("alpha={}", alpha);
                        updateTo(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha));
                    }
                }
            }
        };
        colorLabel.addMouseListener(MouseAlphaListener);
        colorLabel.addMouseMotionListener(MouseAlphaListener);

        btnPipet.setActionListener(e -> ScreenShotUtil.shotColor((color, x, y, wid, hei) -> updateTo(color)));
    }

    private void createUIComponents() {
        root = this;
    }

    /**
     * 外部更新颜色方法
     */
    @Override
    public void updateTo(Color color) {
        this.color = color;
        innerColorComponents.forEach(cc -> cc.updateTo(color));
        //通知外部
        if (colorInvoker != null) colorInvoker.fireColorChanged(this, color);
    }

    /**
     * 将颜色恢复为指定值;不会触发外部的{@link #colorInvoker}的回调
     * 用途:
     * .限制取色范围:外部的colorInvoker收到新颜色后,要恢复成允许范围内的颜色
     *
     * @param color 要恢复成允许范围内的颜色
     */
    public void revertTo(Color color) {
        this.color = color;
        innerColorComponents.forEach(cc -> cc.updateTo(color));
    }


    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        createUIComponents();
        root.setLayout(new GridBagLayout());
        root.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridBagLayout());
        GridBagConstraints gbc;
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.fill = GridBagConstraints.BOTH;
        root.add(panel1, gbc);
        final JLabel label1 = new JLabel();
        label1.setText("临近色");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.EAST;
        panel1.add(label1, gbc);
        final JLabel label2 = new JLabel();
        label2.setText("亮度");
        label2.setToolTipText(" 支持(ctrl+)滚轮");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.EAST;
        panel1.add(label2, gbc);
        final JLabel label3 = new JLabel();
        label3.setText("透明度");
        label3.setToolTipText("支持色板上右键拖拽");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.anchor = GridBagConstraints.EAST;
        panel1.add(label3, gbc);
        final JLabel label4 = new JLabel();
        label4.setText("RGB");
        label4.setToolTipText("支持[上/下/回车]按键");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.anchor = GridBagConstraints.EAST;
        panel1.add(label4, gbc);
        txtColorInt = new ColorTextField();
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.BOTH;
        panel1.add(txtColorInt, gbc);
        nearColorLabel = new NearColorLabel();
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.gridwidth = 3;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets(3, 3, 3, 3);
        panel1.add(nearColorLabel, gbc);
        transparencyPanel = new TransparencyLabel();
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.gridwidth = 3;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets(3, 3, 3, 3);
        panel1.add(transparencyPanel, gbc);
        brightnessLabel = new BrightnessLabel();
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 1;
        gbc.gridwidth = 3;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets(3, 3, 3, 3);
        panel1.add(brightnessLabel, gbc);
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridBagLayout());
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = 3;
        gbc.gridwidth = 2;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.BOTH;
        panel1.add(panel2, gbc);
        txtColorHex = new ColorTextField();
        txtColorHex.setIntStr(false);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.BOTH;
        panel2.add(txtColorHex, gbc);
        final JLabel label5 = new JLabel();
        label5.setText("#");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(0, 10, 0, 0);
        panel2.add(label5, gbc);
        btnPipet = new ImageButton();
        btnPipet.setIcon(new ImageIcon(getClass().getResource("/static/icon/icon_pipet.gif")));
        btnPipet.setToolTipText("屏幕取色");
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.insets = new Insets(0, 3, 0, 0);
        panel2.add(btnPipet, gbc);
        final JPanel spacer1 = new JPanel();
        gbc = new GridBagConstraints();
        gbc.gridx = 3;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        panel2.add(spacer1, gbc);
        colorLabel = new RectangleColorLabel();
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        gbc.fill = GridBagConstraints.BOTH;
        root.add(colorLabel, gbc);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return root;
    }

}
